package cur.tool.common.conifg;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import cur.nature.framework.core.log.LOG;
import cur.nature.framework.core.thread.MyThreadLocal;
import cur.nature.framework.core.util.JWTUtil;
import cur.nature.framework.core.util.StringUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;


@Configuration
@ConditionalOnProperty( value = {"cur.core.server.config.mvc.enable"})
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Value("${cur.core.server.config.mvc.swagger:false}")
    private boolean swagger;

    @Value("${cur.core.server.config.mvc.pattern}")
    private String pattern;
    @Value("${cur.core.server.config.mvc.location}")
    private String[] location;


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new JwtSecurityInterceptor()) //jwt 检验
//                .addPathPatterns("/quant/**");
        registry.addInterceptor(new SecurityInterceptor()) // 分布式session校验
                //排除拦截
                .excludePathPatterns("/admin/v1/api/Admin_User/login")
                .excludePathPatterns("/admin/v1/api/Admin_User/logout")
                .excludePathPatterns("/weixin/v1/Handle")
//                //swagger
                .excludePathPatterns("/v3/api-docs/**","/v3/api-docs/swagger-config","/doc.html", "/webjars/**")
                .excludePathPatterns("/templates/**")
                //拦截路径
                .addPathPatterns("/**");
    }

    //    @Configuration
    public class SecurityInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
            HttpSession session = request.getSession();

//            LOG.info("sessid is : " + session.getId());
            if (session.getAttribute(session.getId()) != null || "OPTIONS".equals(request.getMethod())){
                return true;
            }
            // 校验token
            if (validateJwt(request, response, handler)) {
                return true;
            }
            return true;
//            response.setStatus(401);
//            ServletOutputStream out = response.getOutputStream();
//            out.write(JSON.toJSONString(ResponeObject.unAuthorizeErr("user unauthorized.")).getBytes("utf-8"));
//            out.flush();
//            LOG.info("用户未登录");
//            return false;
        }
    }

    public boolean validateJwt(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader(MyThreadLocal.TOKEN);
        if(StringUtil.isEmpty(token)){
            LOG.warn("token 为空，校验失败。");return false;}
        //校验token
        JWTUtil.Result result = JWTUtil.decodeToken(token);
        //校验通过
        if(JWTUtil.Result.OK == result.getStatus()){return true;}
        //超时
        if (JWTUtil.Result.EXPIRE == result.getStatus()) {
            //方案一：过期时长在一个小时之内，则自动刷新token, 一个小时之后的报错
            long expireHours = (result.getExpireSeconds() / 3600);
            if (expireHours <= 0) {
                String newToken = JWTUtil.encodeToken(result.getData());
                response.addHeader(MyThreadLocal.TOKEN, newToken);
                return true;
            }
            return true;
        }
        return false;
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 静态资源访问路径和存放路径配置
        LOG.info("swagger:"+ swagger + ", pattern: " + pattern + ", location : " + location.toString());
//        registry.addResourceHandler(pattern).addResourceLocations(location);
        // swagger访问配置
        if (swagger) {
            registry.addResourceHandler("doc.html","/webjars/**").addResourceLocations("classpath:/META-INF/resources/","classpath:/META-INF/resources/webjars/");
        }
        registry.addResourceHandler("/tool/**")
                .addResourceLocations("classpath:/static/tool/");
        // 假设你的Jar包中的资源位于"classpath:static/"目录下
//        registry.addResourceHandler("/**")
//                .addResourceLocations("classpath:/static/");

        super.addResourceHandlers(registry);
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 设置允许跨域的路径
        registry.addMapping("/**")
                // 设置允许跨域请求的域名
                .allowedOriginPatterns(CorsConfiguration.ALL)
                // 设置允许的方法
                .allowedMethods(CorsConfiguration.ALL)
                // 是否允许证书 不再默认开启
                .allowCredentials(true)

                //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
//                .exposedHeaders(HttpHeaders.CONTENT_DISPOSITION, "")
                .exposedHeaders("token")//设置token可读取，前端才能获取
                // 跨域允许时间
                .maxAge(3600);
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = converter.getObjectMapper();
        // 生成JSON时,将所有Long转换成String
//        SimpleModule simpleModule = new SimpleModule();
//        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
//        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
//        objectMapper.registerModule(simpleModule);
        // 时间格式化
//        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//        // 设置返回null转为 空字符串""
//        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<>() {
//            @Override
//            public void serialize(Object paramT, JsonGenerator paramJsonGenerator, SerializerProvider paramSerializerProvider) throws IOException, IOException {
//                // 设置返回null转为 空字符串""
//                paramJsonGenerator.writeString("");
//            }
//        });
        // 设置对象转换器
        converter.setObjectMapper(new JacksonObjectMapper());
        // TODO 需要替换 json转换的converter ,可能 index会不对
        converters.add(converters.size()-1, converter);
    }
}
